#!/usr/bin/python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import os
import sys
import json
import uuid
import signal
import shutil
import logging
import asyncio
from bnet_util import Util
from bnet_param import WrtConst
from bnet_param import WrtUserSettings
from bnet_plugin import WrtPluginHub
from bnet_prefix_pool import PrefixPool
from bnet_resources import NetIfPool
from lib.mgr_obconn import WrtObConnManager


class WrtDaemon:

    def __init__(self, param):
        self.param = param
        self.bRestart = False

    async def run(self):
        os.makedirs(WrtConst.varDir, exist_ok=True)
        Util.mkDirAndClear(WrtConst.tmpDir)
        Util.mkDirAndClear(WrtConst.runDir)
        try:
            logging.getLogger().addHandler(logging.StreamHandler(sys.stderr))
            logging.getLogger().setLevel(Util.getLoggingLevel(self.param.logLevel))
            logging.info("Program begins.")

            # load UUID
            if self._loadUuid():
                logging.info("UUID generated: \"%s\"." % (self.param.uuid))
            else:
                logging.info("UUID loaded: \"%s\"." % (self.param.uuid))

            # load configuration
            self.param.settings = WrtUserSettings(self.param)
            logging.info("Configuration loaded.")

            # write pid file
            with open(self.param.RUN_PID_FILE, "w") as f:
                f.write(str(os.getpid()))

            # create main loop
            self.param.mainloop = asyncio.get_running_loop()

            # load plugin hub
            self.param.pluginHub = WrtPluginHub(self.param)
            logging.info("Plugin HUB loaded.")

            # load prefix pool
            self.param.prefixPool = PrefixPool()
            logging.info("Prefix pool loaded.")

            # load resource managers
            self.param.netIfPool = NetIfPool()
            logging.info("Resource managers loaded.")

            # business initialize
            self.param.obConnManager = WrtObConnManager(self.param)
            # self.param.peernetManager = WrtPeernetManager(self.param)
            # self.param.subnetManager = WrtSubnetManager(self.param)
            # self.param.uplinkManager = WrtUpLinkManager(self.param)

            # start main loop
            logging.info("Main loop begins.")
            self.param.mainloop.add_signal_handler(signal.SIGINT, self._sigHandlerINT)
            self.param.mainloop.add_signal_handler(signal.SIGTERM, self._sigHandlerTERM)
            self.param.mainloop.add_signal_handler(signal.SIGHUP, self._sigHandlerHUP)
            while True:
                await asyncio.sleep(3600)
            logging.info("Main loop exits.")
        finally:
            self.param.settings.save()
            logging.shutdown()
            shutil.rmtree(WrtConst.tmpDir)
            if self.bRestart:
                Util.restartProgram()

    def _sigHandlerINT(self):
        logging.info("SIGINT received.")
        self._stop_main_loop()

    def _sigHandlerTERM(self):
        logging.info("SIGTERM received.")
        self._stop_main_loop()

    def _sigHandlerHUP(self):
        logging.info("SIGHUP received.")
        self.bRestart = True
        self._stop_main_loop()
    
    def _stop_main_loop(self):
        """Stop the asyncio event loop"""
        for task in asyncio.all_tasks():
            if task is not asyncio.current_task():
                task.cancel()

    def _loadUuid(self):
        try:
            with open(self.param.CFG_GLOBAL_FILE, "r") as f:
                self.param.uuid = json.load(f)["uuid"]
            return False
        except FileNotFoundError:
            self.param.uuid = self._generateAndSaveUuid()
            return True

    def _generateAndSaveUuid(self):
        cfgObj = dict()
        cfgObj["uuid"] = str(uuid.uuid4())
        with open(self.param.CFG_GLOBAL_FILE, "w") as f:
            json.dump(cfgObj, f, indent=4)
        return cfgObj["uuid"]
